Weaveでは、Scorerを使用してAI出力を評価し、評価メトリクスを返します。Scorerは、AIの出力を取得して分析し、結果の辞書を返します。必要に応じて入力データを参照として使用でき、評価からの説明や推論などの追加情報も出力できます。
Scorerはweave.Evaluationオブジェクトに評価中に渡されます。weaveには2種類のScorerがあります:
  1. 関数ベースのScorer:でデコレートされたシンプルなPython関数@weave.op
  2. クラスベースのScorer:より複雑な評価のためにweave.Scorerを継承するPythonクラス。
Scorerは辞書を返す必要があり、複数のメトリクス、ネストされたメトリクス、LLM評価者からの推論についてのテキストなどの非数値の値を返すことができます。

独自のScorerを作成する

すぐに使えるScorer このガイドではカスタムScorerの作成方法を示していますが、Weaveには様々なpredefined scorerslocal SLM scorersがすぐに使えるように用意されています。以下のようなものがあります:

関数ベースのScorer

これらは@weave.opでデコレートされ、辞書を返す関数です。以下のような単純な評価に最適です:
import weave

@weave.op
def evaluate_uppercase(text: str) -> dict:
    return {"text_is_uppercase": text.isupper()}

my_eval = weave.Evaluation(
    dataset=[{"text": "HELLO WORLD"}],
    scorers=[evaluate_uppercase]
)
評価が実行されると、evaluate_uppercaseはテキストがすべて大文字かどうかをチェックします。

クラスベースのScorer

より高度な評価、特に追加のスコアラーメタデータを追跡する必要がある場合や、LLM評価者に異なるプロンプトを試したり、複数の関数呼び出しを行ったりする場合は、Scorerクラスを使用できます。Requirements:
  1. 以下から継承します:weave.Scorer
  2. scoreメソッドを@weave.opでデコレートして定義します。
  3. scoreメソッドは辞書を返す必要があります。
Example:
import weave
from openai import OpenAI
from weave import Scorer

llm_client = OpenAI()

#highlight-next-line
class SummarizationScorer(Scorer):
    model_id: str = "gpt-4o"
    system_prompt: str = "Evaluate whether the summary is good."

    @weave.op
    def some_complicated_preprocessing(self, text: str) -> str:
        processed_text = "Original text: \n" + text + "\n"
        return processed_text

    @weave.op
    def call_llm(self, summary: str, processed_text: str) -> dict:
        res = llm_client.chat.completions.create(
            messages=[
                {"role": "system", "content": self.system_prompt},
                {"role": "user", "content": (
                    f"Analyse how good the summary is compared to the original text."
                    f"Summary: {summary}\n{processed_text}"
                )}])
        return {"summary_quality": res}

    @weave.op
    def score(self, output: str, text: str) -> dict:
        """Score the summary quality.

        Args:
            output: The summary generated by an AI system
            text: The original text being summarized
        """
        processed_text = self.some_complicated_preprocessing(text)
        eval_result = self.call_llm(summary=output, processed_text=processed_text)
        return {"summary_quality": eval_result}

evaluation = weave.Evaluation(
    dataset=[{"text": "The quick brown fox jumps over the lazy dog."}],
    scorers=[summarization_scorer])
このクラスは、要約を元のテキストと比較することで、要約の質を評価します。

Scorerの仕組み

Scorerのキーワード引数

ScorerはAIシステムからの出力とデータセット行からの入力データの両方にアクセスできます。
  • Input:Scorerがデータセット行から「label」や「target」列などのデータを使用するようにしたい場合は、Scorerの定義にlabelまたはtargetキーワード引数を追加することで簡単に利用できるようになります。
例えば、データセットから「label」という列を使用したい場合、Scorer関数(またはscoreクラスメソッド)のパラメータリストは次のようになります:
@weave.op
def my_custom_scorer(output: str, label: int) -> dict:
    ...
weaveEvaluationが実行されると、AIシステムの出力がoutputパラメータに渡されます。Evaluationは自動的に追加のScorer引数名をデータセット列に一致させようとします。Scorer引数やデータセット列のカスタマイズが難しい場合は、列マッピングを使用できます - 詳細は以下をご覧ください。
  • Output:AIシステムの出力にアクセスするには、Scorer関数のシグネチャにoutputパラメータを含めてください。

を使用した列名のマッピングcolumn_map

時々、scoreメソッドの引数名がデータセットの列名と一致しないことがあります。これはcolumn_mapを使用して修正できます。クラスベースのScorerを使用している場合は、Scorerクラスを初期化するときにcolumn_map属性に辞書を渡します。この辞書はScorerメソッドの引数名をデータセットの列名にマッピングします。順序は:scoreです。{scorer_keyword_argument: dataset_column_name}Example:
import weave
from weave import Scorer

# A dataset with news articles to be summarised
dataset = [
    {"news_article": "The news today was great...", "date": "2030-04-20", "source": "Bright Sky Network"},
    ...
]

# Scorer class
class SummarizationScorer(Scorer):

    @weave.op
    def score(self, output, text) -> dict:
        """
            output: output summary from a LLM summarization system
            text: the text being summarised
        """
        ...  # evaluate the quality of the summary

# create a scorer with a column mapping the `text` argument to the `news_article` data column
scorer = SummarizationScorer(column_map={"text" : "news_article"})
これで、textメソッドのscore引数はnews_articleデータセット列からデータを受け取ります。Notes:
  • 列をマッピングするもう一つの同等のオプションは、Scorerをサブクラス化し、scoreメソッドをオーバーロードして列を明示的にマッピングすることです。
import weave
from weave import Scorer

class MySummarizationScorer(SummarizationScorer):

    @weave.op
    def score(self, output: str, news_article: str) -> dict:  # Added type hints
        # overload the score method and map columns manually
        return super().score(output=output, text=news_article)

Scorerの最終要約

評価中、Scorerはデータセットの各行に対して計算されます。評価の最終スコアを提供するために、出力の戻り値の型に応じてauto_summarizeを提供します。
  • 数値列の平均が計算されます
  • ブール列のカウントと割合
  • その他の列タイプは無視されます
summarizeメソッドをScorerクラスでオーバーライドして、最終スコアを計算する独自の方法を提供できます。summarize関数は以下を期待します:
  • 単一のパラメータscore_rows:これは辞書のリストで、各辞書にはデータセットの単一行に対してscoreメソッドから返されたスコアが含まれています。
  • 要約されたスコアを含む辞書を返す必要があります。
なぜこれが役立つのか?データセットのスコアの最終値を決定する前に、すべての行をスコアリングする必要がある場合。
class MyBinaryScorer(Scorer):
    """
    Returns True if the full output matches the target, False if not
    """

    @weave.op
    def score(self, output, target):
        return {"match": output == target}

    def summarize(self, score_rows: list) -> dict:
        full_match = all(row["match"] for row in score_rows)
        return {"full_match": full_match}
この例では、デフォルトのauto_summarizeはTrueのカウントと割合を返していたでしょう。
詳細を知りたい場合は、CorrectnessLLMJudgeの実装をチェックしてください。

コールにスコアラーを適用する

Weave opsにスコアラーを適用するには、.call()メソッドを使用する必要があります。これにより、操作の結果とそのトラッキング情報の両方にアクセスできます。これにより、スコアラーの結果をWeaveのデータベース内の特定のコールに関連付けることができます。 メソッドの使用方法の詳細については、.call()ガイドのCalling Opsを参照してください。
基本的な例を以下に示します:
# Get both result and Call object
result, call = generate_text.call("Say hello")

# Apply a scorer
score = await call.apply_scorer(MyScorer())
同じコールに複数のスコアラーを適用することもできます:
# Apply multiple scorers in parallel
await asyncio.gather(
    call.apply_scorer(quality_scorer),
    call.apply_scorer(toxicity_scorer)
)
Notes:
  • スコアラーの結果は自動的にWeaveのデータベースに保存されます
  • スコアラーはメイン操作の完了後に非同期で実行されます
  • UIでスコアラーの結果を表示したり、APIを通じてクエリを実行したりできます
ガードレールやモニターとしてスコアラーを使用する詳細情報(本番環境のベストプラクティスや完全な例を含む)については、Guardrails and Monitors guideを参照してください。

使用preprocess_model_input

評価中にモデルに到達する前にデータセットの例を変更するには、preprocess_model_inputパラメータを使用できます。 使用情報と例については、評価前にデータセット行をフォーマットするためのpreprocess_model_inputの使用を参照してください。

スコア分析

このセクションでは、単一のコール、複数のコール、および特定のスコアラーによってスコアリングされたすべてのコールのスコアを分析する方法を示します。

単一のコールのスコアを分析する

単一コールAPI

単一のコールのスコアを取得するには、get_callメソッドを使用できます。
client = weave.init("my-project")

# Get a single call
call = client.get_call("call-uuid-here")

# Get the feedback for the call which contains the scores
feedback = list(call.feedback)

単一コールUI

Call Scores Tab 個々のコールのスコアは、コール詳細ページの「Scores」タブに表示されます。

複数のコールのスコアを分析する

複数コールAPI

複数のコールのスコアを取得するには、get_callsメソッドを使用できます。
client = weave.init("my-project")

# Get multiple calls - use whatever filters you want and include feedback
calls = client.get_calls(..., include_feedback=True)

# Iterate over the calls and access the feedback which contains the scores
for call in calls:
    feedback = list(call.feedback)

複数コールUI

Multiple Calls Tab 複数のコールのスコアは、トレーステーブルの「Scores」列に表示されます。

特定のスコアラーによってスコアリングされたすべてのコールを分析する

スコアラー別のすべてのコールAPI

特定のスコアラーによってスコアリングされたすべてのコールを取得するには、get_callsメソッドを使用できます。
client = weave.init("my-project")

# To get all the calls scored by any version of a scorer, use the scorer name (typically the class name)
calls = client.get_calls(scored_by=["MyScorer"], include_feedback=True)

# To get all the calls scored by a specific version of a scorer, use the entire ref
# Refs can be obtained from the scorer object or via the UI.
calls = client.get_calls(scored_by=[myScorer.ref.uri()], include_feedback=True)

# Iterate over the calls and access the feedback which contains the scores
for call in calls:
    feedback = list(call.feedback)

スコアラー別のすべてのコールUI

最後に、スコアラーによってスコアリングされたすべてのコールを表示したい場合は、UIのScorersタブに移動し、「Programmatic Scorer」タブを選択します。スコアラーをクリックしてスコアラー詳細ページを開きます。 Scorer Details Page 次に、View TracesボタンをScoresの下でクリックして、スコアラーによってスコアリングされたすべてのコールを表示します。 Filtered Calls to Scorer Version これはデフォルトで選択されたバージョンのスコアラーになります。バージョンフィルターを削除して、スコアラーの任意のバージョンによってスコアリングされたすべてのコールを表示することができます。 Filtered Calls to Scorer Name